<script>
import tree from '../tree'
import SelectTree from '@/components/Select/SelectTree'
import SelectCode from '@/components/Select/SelectCode'
import SelectConfig from '@/components/Select/SelectConfig'
import ButtonList from '@/components/ButtonList'
import request from '@/utils/request'
export default {
  name: 'WrapTree',
  provide() {
    return {
      Page: this
    }
  },
  props: {
    tenantId: Number,
    nodeStr: {
      type: String,
      default: ''
    },
    // 字段中作为 label 显示的属性
    nodeLabelKey: {
      type: String,
      default: 'text'
    },
    // 字段中作为 tree 唯一标识属性
    nodeIdKey: {
      type: String,
      default: 'id'
    },
    // 字段中作为 子树 唯一标识属性
    nodeChildrenKey: {
      type: String,
      default: 'children'
    },
    // 字段中作为 叶子 唯一标识属性
    nodeLeafKey: {
      type: String,
      default: 'leaf'
    },
    // 字段中作为 节点选中 唯一标识属性
    nodeCheckedKey: {
      type: String,
      default: 'checked'
    },
    // 字段中作为 大门户菜单一次性数据返回
    showAll: {
      type: Boolean,
      default: false
    },
    tree: {
      type: Object,
      default() {
        return {
          width: {
            type: String,
            default: '200'
          },
          height: {
            type: String,
            default: '500'
          },
          // select tree 组件
          selectTree: {
            type: Object,
            default() {
              return {
                treeParams: {
                  get: {
                    url: '/v1/sys/function/findNextChildNodeTree',
                    nextNodeKey: 'node',
                    idKey: 'id'
                  }
                },
                valueToLabelParams: {
                  url: '/v1/dataProvider/getFunName',
                  idKey: 'funId'
                },
                clearable: true,
                isLoadAllNode: false,
                lazyCache: false,
                // 下拉框出现时是否重新加载数据（或者传入函数自定义操作）
                visibleChangeLoad: [Boolean, Function],
                // 外部传入 selectVal 默认值
                selectCodeVal: [String, Number],
                // 字段中作为获取 select code key
                selectCodeKey: {
                  type: String,
                  default: 'groupId'
                }
              }
            }
          },
          // select code 组件
          selectCode: Object,
          selectConfig: Object,
          // 搜索框相关参数
          search: {
            type: Object,
            default() {
              return {}
            }
          },
          showFilterInput: {
            type: Boolean,
            default: false
          },
          showAll: {
            type: Boolean,
            default: false
          },
          // 懒加载 key, 默认 false
          lazy: {
            type: Boolean,
            default: false
          },
          // 仅仅针对lazy为true时才启用
          expand: {
            type: Boolean,
            default: false
          },
          // 字段中作为获取下一层子节点 key
          nextNodeKey: {
            type: String,
            default: 'node'
          },
          nextNodeValue: {
            type: String,
            default: ''
          },
          // 字段中作为增删改查 key
          idKey: {
            type: String,
            default: 'funId'
          },
          // 顶部面板标题
          title: {
            type: String,
            default: '组织关系'
          },
          // 外部传入菜单按钮数组
          treeMenuButtonList: {
            type: Array,
            default() {
              return []
            }
          },
          // 外部传入树节点按钮数组或函数
          treeOperateButtonList: [Array, Function],
          // 是否显示标题
          isShowHeader: {
            type: Boolean,
            default: true
          },
          // 是否显示节点勾选框
          showCheckbox: {
            type: Boolean,
            default: false
          },
          checkList: {
            type: Array,
            default() {
              return []
            }
          },
          // 父子节点是否强关联
          isCheckStrictly: {
            type: Boolean,
            default: false
          },
          // 勾选父节点不影响子节点，勾选子节点影响父节点
          isCheckParentOnly: {
            type: Boolean,
            default: false
          },
          // 是否只在同一级节点展开
          accordion: {
            type: Boolean,
            default: false
          },
          // 外部传入 icon
          iconSetting: [Function, Object],
          // 外部传入 renderContent 函数
          renderContent: Function,
          // 空白顶部节点
          emptyTopNode: {
            type: Object,
            default() {
              return {}
            }
          },
          // 外部传入获取子节点方法
          getNextChildNode: {
            type: Function,
            default() {
              return () => {}
            }
          },
          // 外部传入删除节点方法
          delNode: {
            type: Function,
            default() {
              return () => {}
            }
          }
        }
      }
    }
  },
  data() {
    return {
      filterSearchText: '',
      treeLoading: false,
      defaultProps: {
        children: this.nodeChildrenKey,
        label: this.nodeLabelKey,
        isLeaf: this.nodeLeafKey
      },
      lazyReload: this.tree.lazy || false,
      defaultExpanded: this.tree.expand || false,
      setTree: [], // 树状菜单数据
      checked: this.tree.checkList || [], // 勾选数组
      lazyDefaultExpanded: [], // 懒加载时默认展开的数组
      filterText: '', // 搜索文本
      currentNode: null, // 当前节点
      currentAction: '',
      selectedLabel: '',

      width: this.tree.width || '200',
      height: this.tree.height,
      isShowPanel: true,
      selectVal:
        (this.tree.selectTree && this.tree.selectTree.selectCodeVal) ||
        (this.tree.selectCode && this.tree.selectCode.selectCodeVal) ||
        (this.tree.selectCofig && this.tree.selectCofig.selectCodeVal) ||
        '',
      selectCodeKey:
        (this.tree.selectTree && this.tree.selectTree.selectCodeKey) ||
        (this.tree.selectCode && this.tree.selectCode.selectCodeKey) ||
        (this.tree.selectConfig && this.tree.selectConfig.selectCodeKey) ||
        'groupId',
      selectTree: this.tree.selectTree || {},
      selectConfig: this.tree.selectConfig || {},
      selectCode: this.tree.selectCode || {},
      searchKey: this.tree.search.searchKey || '',
      nextNodeKey: this.tree.nextNodeKey || 'node',
      idKey: this.tree.idKey || 'funId',
      title: this.tree.title || '组织关系',
      isShowHeader: this.tree.isShowHeader && true,
      search: this.tree.search || {},
      showFilterInput: this.tree.showFilterInput === true || false,
      treeMenuButtonList: this.tree.treeMenuButtonList || [],
      treeOperateButtonList: this.tree.treeOperateButtonList || [],
      isCheckStrictly:
        !this.tree.isCheckParentOnly && (this.tree.isCheckStrictly || false),
      isCheckParentOnly: this.tree.isCheckParentOnly || false,
      emptyTopNode: this.tree.emptyTopNode || {},
      showCheckbox: this.tree.showCheckbox,
      accordion: this.tree.accordion,
      iconSetting:
        this.tree.iconSetting ||
        {
          // icon: 'el-icon-document',
          // svgIcon: 'folder',
          // class: 'test' || ['test1', 'test2']
        },
      renderContent: this.tree.renderContent || this.renderNodeContent,
      getNextChildNode: this.tree.getNextChildNode || function() {},
      delNode: this.tree.delNode || function() {}
    }
  },
  watch: {
    setTree(val, oldVal) {
      if (val && val.length === 0) {
        this.$emit('tree-empty')
      }
      if (oldVal && oldVal.length === 0 && val.length > 0) {
        this.$emit('tree-loaded')
      }
    },
    lazyReload(val) {
      val ? this.handleLazyLoad() : this.refresh()
    },
    tree: {
      deep: true,
      handler: function(val) {
        const selectCodeVal =
          this.selectRef &&
          val[this.selectRef] &&
          val[this.selectRef].selectCodeVal
        this.selectVal = selectCodeVal || ''
        this.load()
      }
    },
    selectVal: {
      handler: function(val) {
        const selectRef =
          this.$slots.selectSlot ||
          (this.selectRef &&
            this[this.selectRef] &&
            Object.keys(this[this.selectRef]).length) ||
          (this.selectTree && Object.keys(this.selectTree).length) ||
          (this.selectCode && Object.keys(this.selectCode).length) ||
          (this.selectConfig && Object.keys(this.selectConfig).length)
        if (selectRef) {
          this.$emit('tree-subSelect', val)
          this.$nextTick(() => {
            this.lazyReload ? this.handleLazyLoad() : this.refresh()
          })
        }
      },
      immediate: true
    },
    filterText(val, oldVal) {
      if (!val && val !== oldVal) {
        this.lazyReload = false
      }
    },
    filterSearchText(val) {
      this.$refs.tree.filter(val)
    }
  },
  computed: {
    nextNodeValue() {
      return this.tree.nextNodeValue || ''
    }
  },
  methods: {
    filterNode(value, data) {
      if (!value) return true
      return data.text.indexOf(value) !== -1
    },
    // 处理导入
    handleImport() {
      this.$emit('tree-import')
    },
    // 处理懒加载默认展开
    lazyExpand(arr) {
      this.lazyDefaultExpanded = []
      const fn = arr => {
        arr.forEach(item => {
          this.lazyDefaultExpanded.push(item[this.nodeIdKey])
          if (item[this.nodeChildrenKey] && item[this.nodeChildrenKey].length) {
            fn(item[this.nodeChildrenKey])
          } else {
            return
          }
        })
      }
      fn(arr)
    },
    // 处理懒加载
    handleLazyLoad(extraParams) {
      let params = {}
      this.treeLoading = true
      if (
        (this.selectRef &&
          this[this.selectRef] &&
          Object.keys(this[this.selectRef]).length) ||
        this.$slots.selectSlot
      ) {
        params[this.selectCodeKey] = this.selectVal
      }
      if (this.searchKey && this.filterText) {
        params[this.searchKey] = this.filterText
      }
      if (this.nextNodeKey && this.nextNodeKey) {
        params[this.nextNodeKey] = this.nextNodeValue
      }
      if (extraParams) {
        params = Object.assign({}, params, extraParams)
      }
      this.getNextChildNode(params)
        .then(({ data }) => {
          this.treeLoading = false
          this.showCheckbox && this.traverseChecked(data)
          // 展开
          this.defaultExpanded && this.lazyExpand(data)
          this.setTree = this.setEmptyTopNode(data)
          // this.setTree = data
          this.$emit('getTreeData', data) // 获取树的数据
          // console.log(data, 'wrapTree::::')
          // 遍历勾选
          this.setAllChecked()
          // 默认选中第一个
          this.filterText ? this.$emit('tree-empty') : this.init()
        })
        .catch(err => {
          console.log(err)
        })
    },
    // 处理搜索
    handleSearch() {
      this.filterText && (this.lazyReload = true)
      this.load()
    },
    handleInputClick() {
      this.handleSearch()
    },
    // 切换顶部菜单
    toggleMenu() {
      this.isShowPanel = !this.isShowPanel
    },
    // 顶部菜单新增
    handleMenuAdd() {
      this.handleAdd()
    },
    handleNodeBtnClick(e) {
      let x = e.target
      while (!x.classList.contains('ButtonList')) {
        x = x.parentNode
      }
      this.currentAction = x.getAttribute('action')
    },
    // 点击节点
    handleNodeClick(data, node) {
      this.currentNode = node
      switch (this.currentAction) {
        case 'plus':
          this.handleAdd(node)
          break
        case 'delete':
          this.handleDel(node)
          break
        case 'custom':
          this.handleCustomOpt(node)
          break
        case 'sync':
          this.handleSync(data, node)
          break
        case 'syncSite':
          this.handleSyncSite(data, node)
          break
        default:
          this.handleCheck(node)
          break
      }
    },
    getSelectedLabel() {
      if (this.$children.length) {
        this.$children.forEach(item => {
          const select = item.$refs['reference']
          select ? (this.selectedLabel = select.currentValue) : ''
        })
      }
    },
    // 【站点默认菜单】需要能够以节点或叶子为单位的部分菜单，增量同步到已存在的站点
    // eslint-disable-next-line
    handleSyncSite(data, node) {
      this.currentAction = ''
      this.$emit('create-dialog', data.id)
    },
    handleSync() {
      return (
        this.$confirm(
          '全量同步机构用户需要3个小时，建议先指定机构或部门再同步。确认需要同步?',
          '提示',
          {
            cancelButtonText: '取消',
            confirmButtonText: '确定',
            type: 'warning'
          }
        )
          .then(() => {
            let path = ''
            let params = ''
            const firstStr = '全部'
            this.getSelectedLabel()

            if (this.tenantId) {
              params = this.tenantId
            } else {
              params = this.nodeStr.replace('部门树', this.selectedLabel)
              if (params.indexOf(firstStr) === -1) {
                params =
                  firstStr + '\\' + params.replace('海关总署', '总署机关')
              }
            }

            params = encodeURI(params)

            this.treeMenuButtonList &&
              this.treeMenuButtonList.length > 0 &&
              this.treeMenuButtonList.forEach(element => {
                if (element.label === '同步') {
                  path = element.path + params
                }
              })

            return request.get(path)
          })
          .then(({ success }) => {
            if (success) {
              this.$message.success('同步成功！')
              this.$parent.$refs.tree.refresh()
            } else {
              this.$message.info('同步异常！')
            }
          })
          // .catch(() => {
          //   this.$message.info("同步失败！")
          // })
          .catch(error => {
            console.log(error)
            this.$message({
              type: error === 'cancel' ? 'info' : 'error',
              message:
                error === 'cancel'
                  ? '已取消同步'
                  : error instanceof Error
                    ? error.message
                    : error
            })
            // return Promise.reject(error)
          })
      )
    },
    handleCustomOpt() {
      this.currentAction = ''
    },
    // 触发新增节点
    handleAdd(node) {
      this.currentAction = ''
      this.$emit('add-treeNode', node)
    },
    // 查看节点
    handleCheck(node) {
      this.currentAction = ''
      this.currentNode = node
      this.$emit('check-treeNode', node)
    },
    // 展开节点
    handleNodeExpand(nodeData, expandFlag) {
      if (!nodeData || !nodeData[this.nodeIdKey]) return
      return new Promise(resolve => {
        const params = {}
        params[this.nextNodeKey] = nodeData[this.nodeIdKey]
        if (
          (this.selectRef &&
            this[this.selectRef] &&
            Object.keys(this[this.selectRef]).length) ||
          this.$slots.selectSlot
        ) {
          params[this.selectCodeKey] = this.selectVal
        }
        this.getNextChildNode(params)
          .then(({ data }) => {
            // 处理非子节点
            data.length > 0 &&
              data.forEach(item => {
                if (this.showAll) {
                  item[this.nodeLeafKey] && (item[this.nodeChildrenKey] = [])
                } else {
                  !item[this.nodeLeafKey] && (item[this.nodeChildrenKey] = [{}])
                }
                // 处理勾选
                this.showCheckbox && this.setInitalChecked(item)
              })

            // children 字段数据监听
            !nodeData[this.nodeChildrenKey]
              ? this.$set(nodeData, 'children', [])
              : (nodeData[this.nodeChildrenKey] = [])
            nodeData[this.nodeChildrenKey] = data
            // 是否需要手动展开
            expandFlag && (this.$refs.tree.getNode(nodeData).expanded = true)
            // 遍历勾选
            this.setAllChecked()

            resolve(data)
          })
          .catch(e => {
            console.log(e)
          })
      })
    },
    // 触发勾选
    handleChecked(data, node) {
      this.checked = node.checkedKeys
      this.$emit(
        'tree-selected',
        this.checked,
        node.checkedNodes,
        node.halfCheckedKeys,
        node.halfCheckedNodes
      )
      const allCheckedNodes = node.halfCheckedNodes.concat(node.checkedNodes)
      this.$emit(
        'check-node',
        allCheckedNodes,
        node.checkedKeys,
        node.checkedNodes,
        node.halfCheckedKeys,
        node.halfCheckedNodes
      )
    },
    // 获取勾选
    getChecked() {
      return this.$refs.tree.getCheckedKeys()
    },
    // 获取半勾选
    getHalfChecked() {
      return this.$refs.tree.getHalfCheckedKeys()
    },
    // 获取勾选 node list
    getCheckedNodes() {
      return this.$refs.tree.getCheckedNodes()
    },
    // 获取半勾选 node list
    getHalfCheckedNodes() {
      return this.$refs.tree.getHalfCheckedNodes()
    },
    // 删除选中
    deleteChecked(id) {
      if (this.checked.length > 0) {
        const index = this.checked.indexOf(id)
        index > -1 && this.checked.splice(index, 1)
      }
    },
    // 初始选中
    setInitalChecked(item) {
      // 父子不关联
      this.isCheckStrictly || this.isCheckParentOnly
        ? item[this.nodeCheckedKey] && this.initalChecked(item)
        : item[this.nodeLeafKey] &&
          item[this.nodeCheckedKey] &&
          this.initalChecked(item)
    },
    initalChecked(item) {
      const index = this.checked.indexOf(item[this.nodeIdKey])
      index === -1 && this.checked.push(item[this.nodeIdKey])
    },
    // 遍历选中
    traverseChecked(arr) {
      arr.length &&
        arr.forEach(item => {
          item.expanded = true
          // 如果有勾选
          this.setInitalChecked(item)
          if (item[this.nodeChildrenKey] && item[this.nodeChildrenKey].length) {
            this.traverseChecked(item[this.nodeChildrenKey])
          }
        })
    },
    // 全部选中
    setAllChecked() {
      this.showCheckbox &&
        this.$nextTick(() => {
          this.$refs.tree.setCheckedKeys(this.checked)
          this.$emit(
            'tree-selected',
            this.getChecked(),
            this.getCheckedNodes(),
            this.getHalfChecked(),
            this.getHalfCheckedNodes()
          )
        })
    },
    // 清空选中
    emptyChecked() {
      this.checked = []
    },
    // 选中当前节点
    setCurrentNodeById(id) {
      this.$refs.tree.setCurrentKey(id)
      this.currentNode = this.getNodeById(id)
    },
    // 获取节点
    getNodeById(id) {
      return this.$refs.tree.getNode(id)
    },
    // 删除 tree 本地节点
    delLocalTree(node) {
      this.$refs.tree.remove(node)
    },
    // 调用删除接口
    delByAjax(node) {
      const params = {}
      params[this.idKey] = node.data[this.nodeIdKey]
      this.delNode(params)
        .then(({ success, code, message }) => {
          if (success || (code && code === '200')) {
            this.$message.success('删除节点成功！')
            this.delLocalTree(node)
            // 从当前树中删除节点, 当前节点为父节点
            let pNode = null
            if (node.parent) {
              pNode = node.parent
            } else {
              if (this.setTree.length === 0) {
                this.handleMenuAdd()
                return
              } else {
                pNode = this.getNodeById(this.setTree[0][this.nodeIdKey])
              }
            }
            this.currentNode = pNode
            this.$refs.tree.setCurrentKey(pNode.data[this.nodeIdKey])
            this.$emit('del-treeNode', pNode)
            // 如果开启勾选，重新触发当前选中
            this.showCheckbox && this.deleteChecked(node[this.nodeIdKey])
          } else {
            if (message) {
              this.$message.warning(message)
            } else {
              return false
            }
          }
        })
        .catch(err => {
          console.log(err)
        })
    },
    // 触发删除节点
    handleDel(node) {
      this.currentAction = ''
      console.log(
        'handleDel -> node.data[this.nodeChildrenKey]',
        node.data[this.nodeChildrenKey]
      )
      if (
        !node.data[this.nodeChildrenKey] ||
        node.data[this.nodeChildrenKey].toString() === ''
      ) {
        this.$confirm('确定删除此节点？', '提示', {
          confirmBottonText: '确认',
          cancelBottomText: '取消',
          type: 'warning'
        })
          .then(() => {
            this.delByAjax(node)
          })
          .catch(() => {
            return false
          })
      } else {
        this.delByAjax(node)
      }
    },
    // 初始选中第一项
    init() {
      this.$nextTick(() => {
        if (this.$refs.tree) {
          const node = this.$refs.tree.getNode(this.setTree[0])
          if (node) {
            if (this.emptyTopNode && Object.keys(this.emptyTopNode).length) {
              node.expanded = true
            }
            this.$refs.tree.setCurrentKey(node.data[this.nodeIdKey])
            this.handleCheck(node)
            this.currentNode = node
          }
        }
      })
    },
    // 折叠节点
    fold() {
      this.setTree.forEach(item => {
        this.$refs.tree.getNode(item).expanded = false
      })
      this.init()
    },
    // 设置顶部空白节点
    setEmptyTopNode(data) {
      if (this.emptyTopNode && Object.keys(this.emptyTopNode).length) {
        this.emptyTopNode = Object.assign(
          {},
          {
            expanded: true,
            id: '',
            leaf: false,
            text: ''
          },
          this.emptyTopNode
        )
        this.emptyTopNode[this.nodeChildrenKey] = data
        return [this.emptyTopNode]
      } else {
        return data
      }
    },
    // 刷新节点
    refresh(extraParams) {
      if (this.lazyReload) this.filterText = ''
      this.treeLoading = true
      let params = {}
      if (
        (this.selectRef &&
          this[this.selectRef] &&
          Object.keys(this[this.selectRef]).length) ||
        this.$slots.selectSlot
      ) {
        params[this.selectCodeKey] = this.selectVal
      }
      if (extraParams) {
        params = Object.assign({}, params, extraParams)
      }
      (
        (Object.keys(params).length && this.getNextChildNode(params)) ||
        this.getNextChildNode()
      )
        .then(({ data }) => {
          this.treeLoading = false
          data &&
            data.forEach(item => {
              if (this.showAll) {
                item[this.nodeLeafKey] && (item[this.nodeChildrenKey] = [])
              } else {
                !item[this.nodeLeafKey] && (item[this.nodeChildrenKey] = [{}])
              }
              // 如果有勾选
              this.showCheckbox && this.setInitalChecked(item)
            })
          this.setTree = this.setEmptyTopNode(data)
          // 遍历勾选
          this.setAllChecked()

          this.init()
        })
        .catch(err => {
          console.log(err)
        })
    },
    // 展开节点
    expand() {
      if (
        !this.setTree ||
        (Array.isArray(this.setTree) && this.setTree.length === 0)
      ) {
        return
      }
      if (this.lazyReload) {
        const expandArr = []
        this.setTree.length > 0 &&
          this.setTree.forEach(item => {
            item[this.nodeChildrenKey] &&
              item[this.nodeChildrenKey].length > 0 &&
              expandArr.push(item)
          })
        const fn = () => {
          const data = expandArr.shift()
          if (data) {
            this.$refs.tree.getNode(data).expanded = true
            if (
              data[this.nodeChildrenKey] &&
              data[this.nodeChildrenKey].length > 0
            ) {
              data[this.nodeChildrenKey].forEach(item => {
                if (
                  item[this.nodeChildrenKey] &&
                  item[this.nodeChildrenKey].length > 0
                ) {
                  expandArr.push(item)
                }
              })
              expandArr.length > 0 && fn()
              // expandArr.length > 0 ? fn() : this.init()
            }
          }
        }
        fn()
      } else {
        const expandArr = []
        this.setTree.length > 0 &&
          this.setTree.forEach(item => {
            !item[this.nodeLeafKey] && expandArr.push(item)
          })
        const fn = () => {
          const item = expandArr.shift()
          item &&
            this.handleNodeExpand(item, true).then(data => {
              data.length > 0 &&
                data.forEach(item => {
                  !item[this.nodeLeafKey] && expandArr.push(item)
                })
              expandArr.length > 0 && fn()
              // expandArr.length > 0 ? fn() : this.init()
            })
        }
        fn()
      }
    },
    // 加载
    load(extraParams) {
      this.emptyChecked()
      this.setTree = []
      this.lazyReload
        ? this.handleLazyLoad(extraParams)
        : this.refresh(extraParams)
    },
    // 判断 select ref 是否出现在 tree 中
    hasSelectRef() {
      let selectRef
      const refs = Object.keys(this.$refs)
      const selectRefs = ['selectCode', 'selectConfig', 'selectTree']
      refs.forEach(item => {
        const index = selectRefs.findIndex(s => s === item)
        index > -1 && (selectRef = selectRefs[index])
      })
      return selectRef
    },
    // 重现加载 selectTree 组件数据
    handleSelectTreeReload(data) {
      this.$refs.selectTree.reload(data)
    },
    // 处理 select tree 下拉框出现时操作
    handleVisibleChange(visible) {
      typeof visible === 'boolean' ? this.$refs.selectTree.reload() : visible()
    },
    // 渲染树节点内容
    renderNodeContent(h, { node, data }) {
      // 处理 icon 数据
      let iconSetting = {}
      typeof this.iconSetting === 'function'
        ? (iconSetting = this.iconSetting(node, data))
        : this.iconSetting instanceof Object
          ? (iconSetting = this.iconSetting)
          : {}
      iconSetting =
        (iconSetting.icon && (
          <i class={[iconSetting.icon].concat(iconSetting.class || [])} />
        )) ||
        (iconSetting.svgIcon && (
          <svg-icon
            icon-class={iconSetting.svgIcon}
            class={[].concat(iconSetting.class)}
          />
        )) ||
        ''

      // 处理 树节点按钮
      let btnList = []
      typeof this.treeOperateButtonList === 'function'
        ? (btnList = this.treeOperateButtonList(node.data, node))
        : this.treeOperateButtonList instanceof Array
          ? (btnList = this.treeOperateButtonList)
          : (btnList = [])

      return (
        <span class='tree-expand'>
          <span v-show={iconSetting}>{iconSetting}</span>
          <span
            class='tree-label'
            title={
              this.$scopedSlots.renderNodeLabel
                ? this.$scopedSlots.renderNodeLabel(node, data)
                : node.label
            }>
            {this.$scopedSlots.renderNodeLabel
              ? this.$scopedSlots.renderNodeLabel(node, data)
              : node.label}
          </span>
          <span
            class='tree-btn'
            on-click={this.handleNodeBtnClick}
            v-show={btnList && btnList.length && this.currentNode === node}>
            <ButtonList props-model={node} operateBtnList={btnList} />
          </span>
        </span>
      )
    },
    // 自定义下拉，包括下拉树组件、代码字典、配置字典等
    // eslint-disable-next-line
    renderSelectSlot(h) {
      if (this.$slots.selectSlot) {
        return <div class='select-wrap'>{this.$slots.selectSlot}</div>
      }
      const defaultSelectOpt = {
        clearable: true,
        dataType: '',
        isLocal: true
      }
      const opt = {
        staticClass: 'select',
        attrs: {
          value: this.selectVal
        },
        on: {
          change: value => {
            this.selectVal = value
          },
          selectTreeEmpty: () => {
            this.selectVal = ''
          }
        }
      }
      let selectSlot
      if (this.selectTree && Object.keys(this.selectTree).length) {
        const defaultSelectTreeOpt = {
          visibleChangeLoad: false,
          isLoadAllNode: false,
          lazyCache: false,
          treeParams: {},
          valueToLabelParams: {},
          clearable: true
        }
        const props = Object.assign({}, defaultSelectTreeOpt, this.selectTree)
        const selectTreeOpt = Object.assign({}, opt, {
          props,
          on: {
            'visible-change': val => {
              props.visibleChangeLoad &&
                val &&
                this.handleVisibleChange(props.visibleChangeLoad)
            },
            change: value => {
              this.selectVal = value
            }
          }
        })
        selectSlot = <SelectTree ref='selectTree' {...selectTreeOpt} />
      } else if (this.selectCode && Object.keys(this.selectCode).length) {
        const selectCodeOpt = Object.assign({}, opt, {
          props: {
            ...Object.assign({}, defaultSelectOpt, this.selectCode)
          }
        })
        selectSlot = <SelectCode ref='selectCode' {...selectCodeOpt} />
      } else if (this.selectConfig && Object.keys(this.selectConfig).length) {
        const selectConfigOpt = Object.assign({}, opt, {
          props: {
            ...Object.assign({}, defaultSelectOpt, this.selectConfig)
          }
        })
        selectSlot = <SelectConfig ref='selectConfig' {...selectConfigOpt} />
      }
      return selectSlot ? <div class='select-wrap'>{selectSlot}</div> : ''
    }
  },
  // eslint-disable-next-line
  render(h) {
    return (
      <div class='wrap-tree'>
        <div
          class='panel-expand-btn'
          on-click={this.toggleMenu}
          v-show={!this.isShowPanel}>
          <span class='title'>{this.title}</span>
          <i class='el-icon-caret-right' title='展开面板'></i>
        </div>
        <div
          class='panel'
          v-show={this.isShowPanel}
          style={{ width: this.width + 'px' }}>
          <div class='topMenu'>
            {// 标题
              this.isShowHeader ? (
                <div class='header'>
                  <span class='title'>{this.title}</span>
                  <i
                    class='el-icon-caret-left'
                    on-click={this.toggleMenu}
                    title='隐藏面板'></i>
                </div>
              ) : (
                ''
              )}
            {this.renderSelectSlot(h)}
            {// 顶部菜单按钮
              this.treeMenuButtonList && this.treeMenuButtonList.length ? (
                <ButtonList
                  class='treeMenuBtn'
                  operateBtnList={this.treeMenuButtonList}
                />
              ) : (
                ''
              )}
            {// 过滤搜索框
              this.showFilterInput ? (
                <c-input
                  placeholder='输入关键字进行过滤'
                  class='search'
                  v-model={this.filterSearchText}></c-input>
              ) : (
                ''
              )}
            {// 搜索框
              this.search && Object.keys(this.search).length ? (
                <c-input
                  class='search-input'
                  placeholder='输入关键字进行过滤'
                  size='small'
                  value={this.filterText}
                  on-input={event => {
                    this.filterText = event
                  }}
                  nativeOnKeydown={ev => {
                    ev.keyCode === 13
                      ? this.handleInputClick(ev, this.filterText)
                      : null
                  }}>
                  <i
                    slot='suffix'
                    class='el-input__icon el-icon-search'
                    on-click={ev =>
                      this.handleInputClick(ev, this.filterText)
                    }></i>
                </c-input>
              ) : (
                ''
              )}
          </div>
          {
            // slot
            this.$slots.default
          }
          <c-scrollbar
            tag='div'
            wrap-class='el-select-dropdown__wrap'
            view-class='el-select-dropdown__list'
            class='is-empty scroll-tree'
            style={{
              'max-height': this.height + 'px',
              height: this.height + 'px',
              'overflow-y': 'auto'
            }}>
            {!this.lazyReload ? (
              <tree
                ref='tree'
                class='expand-tree'
                v-loading={this.treeLoading}
                data={this.setTree}
                show-all={this.showAll}
                node-key={this.nodeIdKey}
                accordion={this.accordion}
                highlight-current
                show-checkbox={this.showCheckbox}
                default-expand-all={false}
                default-checked-keys={this.checked}
                props-props={this.defaultProps}
                check-strictly={this.isCheckStrictly}
                check-parent={this.isCheckParentOnly}
                expand-on-click-node={false}
                render-content={this.renderNodeContent}
                on-node-click={this.handleNodeClick}
                on-node-expand={this.handleNodeExpand}
                on-check={this.handleChecked}
                filter-node-method={this.filterNode}></tree>
            ) : (
              <tree
                ref='tree'
                class='expand-tree'
                v-loading={this.treeLoading}
                data={this.setTree}
                show-all={this.showAll}
                node-key={this.nodeIdKey}
                accordion={this.accordion}
                highlight-current
                show-checkbox={this.showCheckbox}
                default-expand-all={false}
                props-props={this.defaultProps}
                expand-on-click-node={false}
                check-strictly={this.isCheckStrictly}
                check-parent={this.isCheckParentOnly}
                default-expanded-keys={this.lazyDefaultExpanded}
                default-checked-keys={this.checked}
                render-content={this.renderNodeContent}
                on-node-click={this.handleNodeClick}
                on-check={this.handleChecked}
                filter-node-method={this.filterNode}></tree>
            )}
          </c-scrollbar>
        </div>
      </div>
    )
  },
  mounted() {
    this.selectRef = this.hasSelectRef()
    // selectVal watch 改变会立即调用 refresh
    !this.selectRef && this.load()
  },
  components: {
    SelectTree,
    SelectCode,
    SelectConfig,
    tree,
    ButtonList
  }
}
</script>
